package de.westranger.forex.trading.genetic.allel;

import java.util.Random;

import de.westranger.forex.trading.genetic.allel.operator.CompareOperator;
import de.westranger.forex.trading.genetic.allel.operator.CompareOperatorType;
import de.westranger.forex.trading.genetic.allel.operator.EvaluateTerminal;
import de.westranger.forex.trading.genetic.allel.operator.EvaluateTerminalSymbol;
import de.westranger.forex.trading.genetic.allel.operator.LogicalOperator;
import de.westranger.forex.trading.genetic.allel.operator.LogicalOperatorType;
import de.westranger.forex.trading.genetic.allel.operator.Terminal;
import de.westranger.forex.trading.genetic.allel.operator.TerminalSymbol;
import de.westranger.forex.trading.genetic.allel.operator.Util;

public final class RandomNodeFactory implements NodeFactory{
	private final Random r;
	private final LogicalOperatorType[] lot;
	private final CompareOperatorType[] cot;
	private final TerminalSymbol[] termSym;
	private final EvaluateTerminalSymbol[] evalTermSym;

	public RandomNodeFactory(final Random rnd) {
		// remove 'do not use' enums
		this.lot = Util.removeFromArray(LogicalOperatorType.values(),LogicalOperatorType.DO_NOT_USE_ME);
		this.cot = Util.removeFromArray(CompareOperatorType.values(),CompareOperatorType.DO_NOT_USE_ME);
		this.evalTermSym = Util.removeFromArray(EvaluateTerminalSymbol.values(),EvaluateTerminalSymbol.DO_NOT_USE_ME);
		TerminalSymbol[] tmp = Util.removeFromArray(TerminalSymbol.values(),TerminalSymbol.DO_NOT_USE_ME);
		tmp = Util.removeFromArray(tmp,TerminalSymbol.ASK);
		tmp = Util.removeFromArray(tmp,TerminalSymbol.BID);
		tmp = Util.removeFromArray(tmp,TerminalSymbol.TIME);
//		tmp = Util.removeFromArray(tmp,TerminalSymbol.TRIX);
//		tmp = Util.removeFromArray(tmp,TerminalSymbol.MACD_Histogram);
		this.termSym = tmp;
		// init RNG
		this.r = rnd;
	}

	public Node getRandom(final Node root) {
		Node result = null;
		switch (r.nextInt(3)) {
		case 0:
			result = this.getRandomEvaluateTerminal(root);
			break;
		case 1:
			result = this.getRandomCompareOperator(root);
			break;
		case 2:
			result = this.getRandomLogicalOperator(root);
			break;
		default:
			result = null;
		}
		return result;
	}

	public Node getRandomOperator(final Node root){
		Node result;
		if(r.nextBoolean()){
			result = this.getRandomCompareOperator(root);
		}else{
			result = this.getRandomLogicalOperator(root);
		}
		return result;
	}

	public Node getRandomTerminal(final Node root) {
		return new Terminal(root,termSym[r.nextInt(termSym.length)]);
	}

	@Deprecated
	public Node getRandomEvaluateTerminal(final Node root) {
		return new EvaluateTerminal(root,evalTermSym[r.nextInt(evalTermSym.length)]);
	}

	public Node getRandomCompareOperator(final Node root) {
		return new CompareOperator(root, null, null, cot[r.nextInt(cot.length)]);
	}
	
	public Node getRandomLogicalOperator(final Node root) {
		return new LogicalOperator(root, null, null, lot[r.nextInt(lot.length)]);
	}
	
	public Random getRNG(){
		return this.r;
	}
}
